package com.wys.spring;

import com.wys.spring.controller.advice.ControllerRequestBodyAdvice;
import com.wys.spring.controller.advice.ControllerResponseBodyAdvice;
import com.wys.spring.controller.servlet.RequestPathMappingHandler;
import com.wys.spring.filter.RequestEncodingFilter;
import com.wys.spring.filter.SpringMVCLoggingFilter;
import com.wys.spring.health.RedisHealthContributorConfiguration;
import com.wys.spring.health.SpringDataSourceHealthContributorConfiguration;
import com.wys.spring.mybatisplus.MybatisMateHandler;
import com.wys.spring.mybatisplus.MybatisMateProperties;
import com.wys.spring.mybatisplus.generator.CustomLengthIdentifierGenerator;
import com.wys.spring.redis.RedisTempleConfiguration;
import com.wys.spring.security.SpringSecurityBaseConfiguration;
import com.wys.spring.sharding.ShardingRuleSpringRunner;
import com.wys.spring.sharding.TimeShardingStrategy;
import com.wys.spring.swagger.SwaggerConfig;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.jetbrains.annotations.NotNull;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.actuate.autoconfigure.amqp.RabbitHealthContributorAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.*;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.TaskUtils;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.logging.Logger;

@Configuration
@MapperScan(basePackages = {"com.wys.**.dao", "com.wys.**.mapper"})
@ComponentScan({"com.wys.**.service", "com.wys.**.fallback", "com.wys.**.component"})
@Import(value = {RedisHealthContributorConfiguration.class, SpringDataSourceHealthContributorConfiguration.class, RabbitHealthContributorAutoConfiguration.class, SwaggerConfig.class, RedisTempleConfiguration.class})
@EnableConfigurationProperties(value = {MybatisMateProperties.class, SpringCommonProperties.class})
@ConfigurationPropertiesScan(basePackages = "com.wys.**")
public class SpringBaseApplicationConfig {

    private static final Logger log = Logger.getLogger(SpringBaseApplicationConfig.class.getName());

    @Bean
    public SpringSecurityBaseConfiguration springSecurityBaseConfiguration() {
        return new SpringSecurityBaseConfiguration();
    }

    @Bean
    public RequestPathMappingHandler requestPathMappingHandler(SpringCommonProperties springCommonProperties) {
        return new RequestPathMappingHandler(springCommonProperties.getRequestServletProperties());
    }

    @Bean
    @ConditionalOnProperty(prefix = "spring.shardingsphere.auto_create.table", name = "enable", havingValue = "true")
    public ShardingRuleSpringRunner shardingRuleSpringRunner() {
        return new ShardingRuleSpringRunner();
    }

    @Bean
    @ConditionalOnProperty(prefix = "spring.shardingsphere", name = "enabled", havingValue = "true")
    public TimeShardingStrategy timeShardingStrategy() {
        return new TimeShardingStrategy();
    }

    @Bean
    @ConditionalOnProperty(name = "wys.response-encrypt.enable", havingValue = "true")
    public ControllerResponseBodyAdvice controllerResponseBodyAdvice(SpringCommonProperties springCommonProperties) {
        return new ControllerResponseBodyAdvice(springCommonProperties.getResponseEncrypt());
    }

    @Bean
    @ConditionalOnProperty(name = "wys.response-encrypt.enable", havingValue = "true")
    public ControllerRequestBodyAdvice controllerRequestBodyAdvice(SpringCommonProperties springCommonProperties) {
        return new ControllerRequestBodyAdvice(springCommonProperties.getResponseEncrypt());
    }

    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(10000);
        threadPoolTaskScheduler.setErrorHandler(TaskUtils.LOG_AND_SUPPRESS_ERROR_HANDLER);
        return threadPoolTaskScheduler;
    }


    @Bean
    public ApplicationContextHolder applicationContextHolder() {
        ApplicationContextHolder applicationContextHolder = ApplicationContextHolder.getInstance();
        log.info("init applicationContextHolder 完成！！");
        return applicationContextHolder;
    }


    @Bean
    @Primary
    public SpringMVCLoggingFilter springMVCLoggingFilter() {
        return new SpringMVCLoggingFilter();
    }

    @Bean
    @Primary
    public MybatisMateHandler mybatisMateHandler(MybatisMateProperties mybatisMateProperties) {
        return new MybatisMateHandler(mybatisMateProperties);
    }

    @Bean
    @ConditionalOnMissingBean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(@NotNull CorsRegistry registry) {
                registry.addMapping("/**");
            }
        };
    }

    @Bean
    @Primary
    public CustomLengthIdentifierGenerator customLengthIdentifierGenerator() {
        return new CustomLengthIdentifierGenerator();
    }

    @Bean
    @ConditionalOnProperty(prefix = "wys.xXlJobConfig", name = "enable", havingValue = "true")
    public XxlJobSpringExecutor xxlJobSpringExecutor(SpringCommonProperties springCommonProperties) {
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAddress(springCommonProperties.getXXlJobConfig().getAddress());
        xxlJobSpringExecutor.setAccessToken(springCommonProperties.getXXlJobConfig().getAccessToken());
        xxlJobSpringExecutor.setLogRetentionDays(springCommonProperties.getXXlJobConfig().getLogRetentionDays());
        xxlJobSpringExecutor.setAdminAddresses(springCommonProperties.getXXlJobConfig().getAdminAddresses());
        xxlJobSpringExecutor.setLogPath(springCommonProperties.getXXlJobConfig().getLogPath());
        xxlJobSpringExecutor.setIp(springCommonProperties.getXXlJobConfig().getIp());
        xxlJobSpringExecutor.setPort(springCommonProperties.getXXlJobConfig().getPort());
        return xxlJobSpringExecutor;
    }


    @Bean
    @Primary
    public WYSGlobalExceptionHandler wysGlobalExceptionHandler() {
        return new WYSGlobalExceptionHandler();
    }


    /**
     * 设置默认request character encoding 为utf-8
     */
    @Bean
    public RequestEncodingFilter requestEncodingFilter() {
        return new RequestEncodingFilter(null);
    }

}
